CSCI E-92: Application Note 8 Using the PendSV interrupt -------------------------- There is, unfortunately, one more wrinkle in fully-implementing Problem Set 6 -- in particular, in getting SVCYield to work. This application note will describe the problem and then the solution. The simple way to implement SVCYield would be for the SVCYieldImpl function to simply call the exact same code that is used as the SysTick ISR for context switching. The problem is that there is some additional ARM safety checking behavior that throws a fault when we attempt to return from the SysTick ISR function when it is invoked via a function call from an SVC handler (i.e., when it is invoked via a function call from within the implementation of an SVC). This behavior is detailed in the ARM v7-M Architecture Reference Manual, Issue E.b in section B1.5.8 "Exception return behavior" on page B1-595 (ARM v7-M Architecture Reference Manual, Errata markup, ARM DDI 0403Derrata 2010_Q3 in section B1.5.8 "Exception return behavior" on page B1-652). Specifically under "Integrity checks on exception return" on page B1-596 in Issue E.b (page B1-654 in Errata markup, ARM DDI 0403Derrata 2010_Q3) it states, The integrity checks test the following on an exception return: o The Exception number being returned from, as held in the IPSR at the start of the return, is listed in the SCB as being active. o Normally, if at least one exception other than the returning exception is active, the return must be to Handler mode. This checks for a mismatch of the number of exception returns. Software can use the CCR.NONBASETHRDENA to disable this check, see Configuration and Control Register, CCR on page B3-720. o On a return to Thread mode, the value restored to the IPSR Exception number field must be 0. o On a return to Handler mode, the value restored to the IPSR Exception number field must not be 0. o EXC_RETURN[3:0] must not be a reserved value, see Table B1-8 on page B1-653. Any failed check causes an INVPC UsageFault, with the EXC_RETURN value in the LR. The specific problem is that when we call the SysTick ISR function from within the SVCYieldImpl, the IPSR still has the SVC exception number stored in it (if you look there you will see the decimal value 11, the interrupt vector number for SVCall) yet we may be switching to a process that was not also inside an SVC when it was interrupted -- therefore, the SVCALLACT bit would not be set. You might think that this could be solved by pushing and popping the IPSR exception number field along with the SVCALLACT bit in the SHCSR register, and you would be correct if we were able to do so. Unfortunately, although we are able to read the IPSR exception number field, we are not able to write it (see section B5.2.3 "MSR" on page B5-735 in Issue E.b (page B5-805 in Errata markup, ARM DDI 0403Derrata 2010_Q3) where it states, "The IPSR fields are read-only. The processor ignores any attempt by privileged software to write to them."). Moreover, in general, if any SVC implementation can be suspended so another process can execute (either through an interrupt or by calling yield), the context switching needs to be accomplished by code running under a different interrupt (that is, other than the SVC interrupt number). There is a solution to this problem, but, it involves utilizing (yet another) interrupt. The core ARM architecture includes an interrupt that can be triggered by setting a bit. This interrupt, referred to as the PendSV (i.e., pending supervisor call) interrupt, can be requested by setting the PENDSVSET bit in the ICSR register (see B3.2.4 "Interrupt Control and State Register, ICSR" on page B3-655 in Issue E.b (page B3-713 in Errata markup, ARM DDI 0403Derrata 2010_Q3)). The PendSV interrupt has its own vector table entry (vector number 14) and its own priority (see the SHPR3 register, field PRI_14). The priority of PendSV can be altered using the SHPR3 (System Handler Priority Register 3) on page B3-724 of the ARM v7-M Architecture Reference Manual, Errata markup manual. For similar priority setting code, see the svcInit_SetSVCPriority function in svc.c. Here is a synopsis for how to correctly handle a request to yield quantum in the SVCYieldImpl. Set the priority of the PendSV interrupt to the same value as the SysTick interrupt -- that is, 14. This allows PendSV to interrupt the SVC, but does not allow a SysTick interrupt to interrupt it. In the vector table, enter the same context switching function that SysTick uses for PendSV also. When any SVC implementation wants to yield, it simply ORs in the PENDSVSET bit (named SCB_ICSR_PENDSVSET_MASK in MK70F12.h) into the ICSR register (named SCB_ICSR in MK70F12.h).